/*
 * File:        bufferList.h
 * Authors:     Jonathan Kotker (ee122-bw) and Shaan Mulchandani (ee122-bv)
 * Description: This header file defines the list of current buffers.
 */

#ifndef _BUFFERLIST_H
#define	_BUFFERLIST_H

#include "constants.h"
#include "bufferListNode.h"

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    /* Head of the linked list of all buffers. */
    bufferListNode* head;

} bufferList;

/*
 * Returns the buffer node associated with the given file descriptor,
 * and NULL otherwise.
 */
bufferListNode* accessBuffer(bufferList* list, int fileDescriptor) {
    if (list == NULL) return NULL;

    // Node corresponding to the player.
    bufferListNode* bufferNode = list->head;

    while (bufferNode) {
        if (bufferNode->fileDescriptor == fileDescriptor) {
            return bufferNode;
        }

        bufferNode = bufferNode->next;
    }

    return NULL;
};

/*
 * Deallocates the dynamic memory allocated to this list.
 */
void clearBufferList(bufferList* list) {
    bufferListNode* currNode;
    bufferListNode* nextNode;
    currNode = list->head;

    while (currNode != NULL) {
        nextNode = currNode->next;
        free(currNode);
        currNode = nextNode;
    }
};

/* If the buffer associated with the given file descriptor does not already
 * exist in the list, adds a new buffer to the list, and associates the
 * buffer with the provided file descriptor. Otherwise, does nothing. */
void addBuffer(bufferList* list, int fileDescriptor) {
    if (list == NULL) return;

    // Node corresponding to the buffer.
    bufferListNode* listNode;
    if ((listNode = accessBuffer(list, fileDescriptor)) == NULL) {
        bufferListNode* newBufferNode;
        if (((newBufferNode = malloc(sizeof (bufferListNode))) == NULL)) {
            fprintf(stdout, "No free space available to allocate. \n");
            clearBufferList(list);
            exit(EXIT_FAILURE);
        }

        newBufferNode->fileDescriptor = fileDescriptor;
        newBufferNode->incomingPosition = 0;
        
        newBufferNode->next = list->head;
        newBufferNode->prev = NULL;

        if (newBufferNode->next != NULL)
            newBufferNode->next->prev = newBufferNode;

        list->head = newBufferNode;
    }
};

/* If the player with the given file descriptor exists in the list,
 * removes the player from the list. Otherwise, does nothing. */
void removeBuffer(bufferList* list, int fileDescriptor) {
    if (list == NULL) return;

    // Node corresponding to the player.
    bufferListNode* bufferNode;

    if ((bufferNode = accessBuffer(list, fileDescriptor)) != NULL) {
        if (list->head != bufferNode)
            bufferNode->prev->next = bufferNode->next;
        else
            list->head = bufferNode->next;

        bufferNode->next = NULL;
        free(bufferNode);
    }
};

#endif	/* _BUFFERLIST_H */
